<?php

/*
 * $Id: base.php 14 2011-01-23 07:35:00Z LEON $
 * $Author: LEON $
 * $LastChangedDate: 2011-01-23 07:35:00 +0000 (Sun, 23 Jan 2011) $
 * $Revision: 14 $
 */

namespace cmFly\controller;

use cmFly\controller\system\config;

abstract class base extends system\context_store {

    /**
     *
     * @var \cmFly\system\config\handler_base
     */
    private $config;
    private $view;
    private $parent;
    private $config_dir;
    private $logs_dir;
    private $tmp_dir;
    private $views_dir;
    private $db;

    const OPT_DEFAULT_ROUTE='default_route';
    const OPT_ERROR_MODULE='error_module';
    const OPT_REDIRECTS_MAXIMUM='redirects_maximum';
    const OPT_MODULE_DEFAULT_ACTION='module_default_action';

    public function __construct($controller_root, base $parent=NULL) {
	$this->set_parent($parent);
	$this->set_config_dir($controller_root . '/configuration');
	$this->set_views_dir($controller_root . '/views');
    }

    public function get_parent() {
	return $this->parent;
    }

    protected function set_parent(base $parent=NULL) {
	$this->parent = $parent;
    }

    public function set_config_dir($dir) {
	if (substr($dir, -1) == '/') {
	    $dir = substr($dir, 0, -1);
	}
	$this->config_dir = $dir;
    }

    public function get_config_dir() {
	return $this->config_dir;
    }

    protected function set_config(config\handler_base $config) {
	$this->config = $config;
    }

    public function get_config() {
	if (!isset($this->config)) {
	    $parent_config = NULL;
	    if ($parent = $this->get_parent()) {
		$parent_config = $parent->get_config();
	    }
	    $this->config = new config\handlers\yaml($this->get_config_dir(), $parent_config);
	}
	return $this->config;
    }

    public function set_logs_dir($dir) {
	$this->logs_dir = $dir;
    }

    public function get_logs_dir() {
	if (isset($this->logs_dir)) {
	    return $this->logs_dir;
	}
	if ($parent = $this->get_parent()) {
	    return $parent->get_logs_dir();
	}
	throw new exceptions\error('Logs dir don\'t setted!');
    }

    public function set_tmp_dir($dir) {
	$this->tmp_dir = $dir;
    }

    public function get_tmp_dir() {
	if (isset($this->tmp_dir)) {
	    return $this->tmp_dir;
	}
	if ($parent = $this->get_parent()) {
	    return $parent->get_logs_dir();
	}
	throw new exceptions\error('Tmp dir don\'t setted!');
    }

    protected function set_views_dir($views_dir) {
	$this->views_dir = $views_dir;
    }

    public function get_views_dir() {
	return $this->views_dir;
    }

    public function set_view(\cmFly\view\iView $view) {
	$this->view = $view;
    }

    public function get_view() {
	if (isset($this->view)) {
	    return $this->view;
	}
	$this->view = new \cmFly\view\php($this, $this->get_views_dir());
	return $this->view;
    }

    /**
     * @param string $to
     * if $to=NULL select default connection
     * @return \cmFly\db\PDO
     */
    public function get_database($to=NULL) {
	if (!$to) {
	    $to = $this->get_database_default_name();
	}
	if ($this->db[$to]) {
	    return $this->db[$to];
	}
	if ($this->get_config()->exists('db') && isset($this->get_config()->db[$to])) {
	    $opt = $this->get_config()->db[$to];
	    $db = new \cmFly\db\PDO($opt['dbType'] . ':host=' . $opt['dbHost'] . ';dbname=' . $opt['dbName'], $opt['dbUser'], $opt['dbPass']);
	    $db->exec('SET NAMES UTF8');
	    $this->db[$to] = $db;
	    return $db;
	} else {
	    throw new exceptions\error('Can\'t find database connection \'' . $to . '\' config file!');
	}
    }

    public function get_database_default_name() {
	return 'default';
    }

    public function error_page($error_num, $error_string='',$last_error=NULL) {
	return $this->get_parent()->error_page($error_num, $error_string,$last_error);
    }

    public function get_opt($opt) {
	return $this->get_parent()->get_opt($opt);
    }

    public static function parse_internal_path($path) {
	$arr = explode('/', $path);
	if ($count = count($arr)) {
	    $count--;
	    if (empty($arr[$count])) {
		array_pop($arr);
	    }
	    if ($count > 0 && empty($arr[0])) {
		array_shift($arr);
	    }
	}
	return $arr;
    }

    /**
     * Run user defined source in the current controller context
     * @param \Closure $user_func
     */
    public function run(\Closure $user_func) {
	$tmp_context = self::get_context();
	self::set_context(new system\context($this));

	$ret = $user_func();

	self::set_context($tmp_context);
	return $ret;
    }

    /**
     * Run controller.
     * Change the current context
     * and swap context to a parent in the end.
     */
    abstract public function exec();
}